COM Interfaces |
The figure below shows the main COM interfaces. As you may remember, all COM objects must implement IUnknown, which is why this interface is considered the Mother Interface in COM. There are other COM interfaces such as: IOleClientSite, IOleControlSite, IAdviseSink, IServiceProvider, IOleInPlaceSiteWindowless, IOleInPlaceSiteEx, IOleInPlaceSite, IOleWindow, IOleInPlaceFrame, IOleInPlaceUIWindow, IOleContainer, IParseDisplayName, and IBindHost. You perform a search over the Internet to know more about these interfaces. You may explore the *.idl files under C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\um to know what functions these interfaces have. La figura de abajo muestra las interfaces principales de COM. Como usted debe recordar, todos los objetos COM deben implementar IUnknown, por lo que esta interface se considera la Madre de las Interfaces en COM. Hay otras interfaces COM tales como: IOleClientSite, IOleControlSite, IAdviseSink, IServiceProvider, IOleInPlaceSiteWindowless, IOleInPlaceSiteEx, IOleInPlaceSite, IOleWindow, IOleInPlaceFrame, IOleInPlaceUIWindow, IOleContainer, IParseDisplayName, and IBindHost. You perform a search over the Internet to know more about these interfaces. Usted puede hacer una búsqueda en la Internet para conocer más acerca de estas interfaces. Usted puede explorar los archivos *.idl en la carpeta C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\um para conocer cuales funciones tienen estas interfaces. |
Tip |
Several of these interfaces are declared in Oleidl.idl (Oleidl.h) and Objidl.idl (Objidl.h). These file are part of Windows Kits, i.e., C:\Program Files (x86)\Windows Kits\8.1\Include\um Varias de estas interfaces están declaradas en Oleidl.idl (Oleidl.h) y Objidl.idl (Objidl.h). Esto archivos son partes de los Windows Kits, por ejemplo: C:\Program Files (x86)\Windows Kits\8.1\Include\um |
COM Server using Wintempla |
Wintempla provides some classes to create a COM server:
Wintempla proporciona algunas clases para crear servidores COM:
|
Tip |
The next example shows how to use the Wintempla macros to implement the IUnknown interface. In the program suppose that the Basic class implements three interfaces: IMinMax, IStatistics, and IManager. These three interfaces are derived from the IUnknown interface. In the IUNKNOWN_BEGIN macro, you may use any of the interfaces that the class implements. You do not need to add any code to the Basic.cpp file to implement IUnknown using the Wintempla macros. El siguiente ejemplo ilustra cómo usar los macros de Wintempla para implementar la interface IUnknown. En el programa suponga que la clase Basic implementa tres interfaces: IMinMax, IStatistics y IManager. Estas tres interfaces se derivan de la interface IUnknown. En el macro IUNKNOWN_BEGIN se debe colocar cualquiera de las interfaces de la clase. Usted no necesita agregar ningún código al archivo Basic.cpp para implementar IUnknown usando los macros de Wintempla. |
Basic.h |
class Basic : public IMinMax, public IStatistics, public IManager { public: Basic(void); ~Basic(void); //_____________________________________________________ IUnknown IUNKNOWN_BEGIN (IManager) QUERY_INTERFACE(IID_IMinMax, IMinMax) QUERY_INTERFACE(IID_IStatistics, IStatistics) QUERY_INTERFACE(IID_IManager, IManager) IUNKNOWN_END //_______________________________________________________IMinMax ... //______________________________________________________ IStatistics ... //_______________________________________________________ IManager ..; }; |
Tip |
The next example shows how to use the Wintempla macros to implement the IDispatch interface. In the program suppose that the Basic class implements three interfaces: IMinMax, IStatistics, and IManager. Suppose that the IStatistics and the IManager interfaces are derived from IUnknown. Suppose that the IMinMax interface is from the IDispatch interface. In the IUNKNOWN_BEGIN macro, you may use any of the interfaces that the class implements. You do not need to add any code to the Basic.cpp file to implement IDispatch using the Wintempla macros. El siguiente ejemplo ilustra cómo usar los macros de Wintempla para implementar la interface IDispatch. En el programa suponga que la clase Basic implementa tres interfaces: IMinMax, IStatistics y IManager. Suponga que las interfaces IStatistics y IManager se derivan de la interface IUnknown. Suponga que la interface IMinMax se deriva de la interface IDispatch. En el macro IUNKNOWN_BEGIN se debe colocar cualquiera de las interfaces de la clase. Usted no necesita agregar ningún código al archivo Basic.cpp para implementar IDispatch usando los macros de Wintempla. |
Basic.h |
class Basic : public IMinMax, public IStatistics, public IManager { public: Basic(void); ~Basic(void); //_____________________________________________________ IUnknown IUNKNOWN_BEGIN (IManager) QUERY_INTERFACE(IID_IStatistics, IStatistics) QUERY_INTERFACE(IID_IManager, IManager) QUERY_INTERFACE(IID_IMinMax, IMinMax) QUERY_INTERFACE(IID_IDispatch, IDispatch) IUNKNOWN_END //_____________________________________________________ IDispatch IDISPATCH_IMPL(LIBID_MyLib, IID_IMinMax, 1, 0) //_______________________________________________________IMinMax ... //______________________________________________________ IStatistics ... //_______________________________________________________ IManager ..; }; |
Tip |
See Wintempla > Registry > Register a COM server to learn about how to register a COM server. Vea Wintempla > Registry > Register a COM server para aprender acerca de cómo registrar un servidor COM. |
Interface Definition Language |
Each interface must be declared (defined) in:
Cada interface debe declarada (definida) en:
|
The MIDL Compiler |
An interface definition language file (*.idl) is compiled with the MIDL compiler to produce several files that must be included in your project. For a MyServer.idl file the MIDL compiler will generate the following files:
Un archivo de lenguaje de definición de interface (*.idl) se compila con el compilador MIDL para producir varios archivos que deben ser incluidas en su proyecto. Para un archivo MyServer.idl el compilador de MIDL generará los siguientes archivos:
|
Tip |
As the MIDL compiler will generate the files described in the previous definition when the project is compiled. You cannot include these files until the project has been compiled at least once. Como el compilador de MIDL generará los archivos descritos en la definición previa cuando el proyecto sea compilado. Usted no puede incluir estos archivos hasta que el proyecto se haya compilado al menos una vez. |
Type Library |
A type library is stored in a file with the extension tlb. A type library file is generated when the idl file is compiled. The type library file (*.tlb) can be open with the Object Browser to explore the library. However, the type library file is placed in the hard drive of the computer, and the Windows registry must be modified (creating keys to indicate where the type library file is located) so that all programs (including the Object Browser) in the computer can find the this file. Una librería de tipos (type library) se almacena en un archivo con la extensión tlb. Un archivo de librería de tipos se genera cuando el archivo idl se compila. El archivo tlb puede abrirse con el Explorador de Objetos para explorar la librería. Sin embargo, el archivo de tlb se coloca en el disco duro de la computadora y el Registro de Windows debe modificarse (creando llaves para almacenar donde se encuentra el archivo tlb) para que todos los programas (incluyendo el Explorador de Objetos) en la computadora puedan encontrar el archivo tlb. |
Windows Registry, COM and Wintempla |
COM classes (declared in an Interface Definition Language file *.idl) and Type libraries (*.tlb) must be updated in Windows registry as shown in the figures below. Observe that there are basically three places where the registration occurs: HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT/TypeLib and HKEY_CLASSES_ROOT/CLSID. Wintempla provides some functions to register and remove from the registry COM classes and type libraries.
Las clases COM (declaradas en un un archivo escrito en el Lenguaje de Definición de Interfaces *.idl) y las librerías de tipo (type libraries, *.tlb) debe ser dadas de alta en el registro de Windows como se muestra en las figuras de abajo. Observe que hay tres partes básicas dónde le proceso de registro ocurre: HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT/TypeLib and HKEY_CLASSES_ROOT/CLSID. Wintempla proporciona algunas funciones para registrar y remover del registro una clase COM y una librería de tipo:
|
#import |
In order to be able to use the #import command with a tlb file or a dll file, you must store the tlb file inside the main DLL file as a resource. A fin de poder usar el comando #import con un archivo tlb o un archivo dll, usted debe almacenar el archivo tlb dentro del archivo principal de la DLL como un recurso. |
Problem 1 |
Create a COM Server using Wintempla called SimpleServer. When creating the Wintempla project choose: COM Server. This project does not use the Active Template Library (ATL). Cree un servidor COM usando Wintempla llamado SimpleServer. Cuando cree el proyecto de Wintempla escoja: COM Server. Este proyecto no usa la Librería Plantillas Activas (ATL). |
Step A |
Edit the SimpleServer.idl file. You may reuse the uuids generated by the New Project wizard. The library SimpleServer will have only one COM class called Basica. The COM class will have only one interface called IMathFunc. This interface will be declared as dual, that is, it will be derived from the interface IDispatch (instead of being derived from the IUnknown interface). Script clients will use the interface IDispatch to connect to the server. Other clients will use the IMathFunc interface. Edite el archivo SimpleServer.idl. Usted puede reusar los uuids generados por el asistente de nuevo proyecto. La librería SimpleServer tendrá solamente una clase COM llamada Basica. La clase COM tendrá solamente una interface llamada IMathFunc. Esta interface será declarada como dual, esto es, será derivada de la interface IDispatch (en lugar de derivarse de la interface IUnknown). Los clientes del tipo script usar la interface IDispatch para conectase al servidor. Otros clientes usarán la interface IMathFunc. |
SimpleServer.idl |
//__________________________________________ SimpleServer.idl // import "oaidl.idl"; import "ocidl.idl"; //_______________________________________________________________ IMathFunc (dual) [ object, uuid(5311fd15-df8d-445a-9d6a-e82eb36cc54c), dual, nonextensible, pointer_default(unique) ] interface IMathFunc : IDispatch{ [propget, id(1), helpstring("Returns the minimum")] HRESULT Minimum([out, retval] DOUBLE* minimum); [propget, id(2), helpstring("Returns the maximum")] HRESULT Maximum([out, retval] DOUBLE* maximum); [propget, id(3), helpstring("Returns the mean")] HRESULT Mean([out, retval] DOUBLE* mean); [propget, id(4), helpstring("Returns the variance")] HRESULT Variance([out, retval] DOUBLE* variance); [id(5), helpstring("Inserts a new value")] HRESULT Add([in] DOUBLE value); // THIS IS NOT A PROPGET [propget, id(6), helpstring("Returns the number of values")] HRESULT Count([out, retval] LONG* count); [id(7), helpstring("Removes all previous values")] HRESULT Clear(void); // THIS IS NOT A PROPGET }; //_______________________________________________________________ SimpleServerLib [ uuid(9ca2796c-bc89-47f2-9034-a6a5a4b45a03), version(1.0), ] library SimpleServerLib { importlib("stdole2.tlb"); [ uuid(2867cb0d-f42c-45db-b448-f2f460d834ce) ] coclass Basica { [default] interface IMathFunc; }; }; |
Step B |
Compile your project to generate the files: SimpleServer.tlb, SimpleServer_i.c and SimpleServer_h.h. Compile el proyecto para generar los archivos: SimpleServer.tlb, SimpleServer_i.c y SimpleServer_h.h. |
Step C |
From the Tools menu click on Add Wintempla Item and add IUnknown Class called Basica. Edit the Basica.h file. Desde el menú de Herramientas haga clic enAdd Wintempla Item y agregue una IUnknown Class llamada Basica. Edite el archivo Basica.h. |
Basica.h |
#pragma once #include "SimpleServer_i.c" #include "SimpleServer_h.h" class Basica : public IMathFunc { public: Basica(); ~Basica(); //_____________________________________________________ IUnknown IUNKNOWN_BEGIN(IMathFunc) QUERY_INTERFACE(IID_IMathFunc, IMathFunc) QUERY_INTERFACE(IID_IDispatch, IDispatch) IUNKNOWN_END //_____________________________________________________ IDispatch IDISPATCH_IMPL(LIBID_SimpleServerLib, IID_IMathFunc, 1, 0) //_____________________________________________________ IMathFunc STDMETHOD(get_Minimum)(DOUBLE * minimum); STDMETHOD(get_Maximum)(DOUBLE * maximum); STDMETHOD(get_Mean)(DOUBLE * mean); STDMETHOD(get_Variance)(DOUBLE * variance); STDMETHOD(Add)(DOUBLE value); STDMETHOD(get_Count)(LONG* count); STDMETHOD(Clear)(void); private: int count; double sum; double sq_sum; double minimum; double maximum; }; |
Step D |
Edit the Basica.cpp file. Edite el archivo Basica.cpp. |
Basica.cpp |
#include "stdafx.h" #include "Basica.h" Basica::Basica() { count = 0; sum = 0.0; sq_sum = 0.0; minimum = 0.0; maximum = 0.0; } Basica::~Basica() { } STDMETHODIMP Basica::get_Minimum(DOUBLE * minimum) { *minimum = this->minimum; return S_OK; } STDMETHODIMP Basica::get_Maximum(DOUBLE * maximum) { *maximum = this->maximum; return S_OK; } STDMETHODIMP Basica::get_Mean(DOUBLE * mean) { *mean = sum/count; return S_OK; } STDMETHODIMP Basica::get_Variance(DOUBLE * variance) { *variance = sq_sum/(count-1) - (sum*sum)/(count*(count-1)); return S_OK; } STDMETHODIMP Basica::Add(DOUBLE value) { sum += value; sq_sum += (value*value); // if (count == 0) { minimum = value; maximum = value; } else { if (value < minimum) minimum = value; if (value > maximum) maximum = value; } count++; return S_OK; } STDMETHODIMP Basica::get_Count(LONG* count) { *count = this->count; return S_OK; } STDMETHODIMP Basica::Clear(void) { count = 0; sum = 0.0; sq_sum = 0.0; minimum = 0.0; maximum = 0.0; return S_OK; } |
Step E |
Edit the SimpleServer.cpp file. Wintempla provides the FACTORY_CREATE macro, and the Com::ClassFactory class to implement the DllGetClassObject function as shown in the code below. Edite el archivo SimpleServer.cpp. Wintempla proporciona el macro FACTORY_CREATE, y la clase Com::ClassFactory para implementar la función DllGetClassObject como se muestra en el código de abajo. |
SimpleServer.cpp |
//________________________________________________________________________________SimpleServer.cp #include "stdafx.h" #include "Basica.h" BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG reason, LPVOID lpReserved) { return Com::Base::Begin(hInstance, reason); } STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) { if (rclsid == CLSID_Basica) { FACTORY_CREATE(Basica) } //else (rclsid == CLSID_OtherClass) //{ // FACTORY_CREATE(OtherClass) //} return S_OK; } STDAPI DllCanUnloadNow() { return Com::Base::CanUnloadNow(); } STDAPI DllRegisterServer(void) { HRESULT hr1 = Com::Base::RegisterComClass(LIBID_SimpleServerLib, CLSID_Basica, L"selo", L"Basica", 1); HRESULT hr2 = Com::Base::RegisterTypeLib(LIBID_SimpleServerLib, 1, 0); if (FAILED(hr1)) return hr1; if (FAILED(hr2)) return hr2; return S_OK; } STDAPI DllUnregisterServer(void) { HRESULT hr1 = Com::Base::UnRegisterComClass(LIBID_SimpleServerLib, CLSID_Basica); HRESULT hr2 = Com::Base::UnRegisterTypeLib(LIBID_SimpleServerLib, 1, 0); if (FAILED(hr1)) return hr1; if (FAILED(hr2)) return hr2; return S_OK; } |
Step F |
Change the configuration to Release and Rebuild the solution. The SimpleServer.dll file will be created at SimpleServer\Release folder. The SimpleServer.tlb file will be created at SimpleServer\SimpleServer\Release or SimpleServer\SimpleServer. Create a new permanent folder to install your library, and then copy the DLL and TLB files to this folder. Cambie la configuración a Release y Reconstruya la solución. El archivo SimpleServer.dll será creado en la carpeta de SimpleServer\Release. El archivo SimpleServer.tlb será creado en SimpleServer\SimpleServer\Release o SimpleServer\SimpleServer. Cree una carpeta permanente para instalar su librería, y entonces copie la DLL y la TLB a este folder. |
Step G |
Open a CMD window as administrator (use the context menu to run CMD as administrator), and navigate to the folder where SimpleServer.dll was copied. Register the library using regsvr32.exe. To remove the library from the computer registry, you can use regsvr32 -u SimpleServer.dll Abra una ventana de CMD como administrador (use el menú de contexto para ejecutar CMD como administrador), y navegue a la carpeta dónde se copie el archivo SimpleServer.dll. Registre la librería usando regsvr32.ese. Para remover la librería del registro de la computadora, usted puede usar regsvr32 -u SimpleServer.dll |
MSDOS: cmd.exe |
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\windows\system32>cd.. C:\Windows>cd.. C:\>cd Users\selo C:\Users\selo\regsvr32 SimpleServer.dll |
Step H |
Use the Object Browser to check that your SimpleServer library is properly installed in the computer. Use el Explorador de objetos para verificar que su librería Simple Server esta apropiadamente instalada en la computadora. |
Problem 2 |
Create a Wintempla dialog application called MathClient to test the COM server created in the previous problem. You must import the file SimpleServer.dll (or SimpleServer.tlb) to create the respective header files. Cree una aplicación de Wintempla de diálogo llamada MathClient para probar el servidor COM creado en el problema previo. Usted debe importar el archivo SimpleServer.dll (o SimpleServer.tlb) para crear el archivo de encabezado respectivo. |
Step A |
Add the following line at the end of the stdafx.h file. Compile the project. Move the SimpleServer.tlh and SimpleServer.tli files from the Debug folder to the MathClient project folder. After this, you can remove the import command from the stdafx.h file. In some cases, it is necessary to edit the SimpleServer.tlh file by adjusting the path of the #include "SimpleServer.tli" line near the end of the file. Agregue la siguiente línea al final del archivo stdafx.h. Compile el proyecto. Compile el proyecto. Mueva los archivos SimpleServer.tlh y SimpleServer.tli desde la carpeta de Debug a la carpeta del proyecto MathClient. Después de esto, usted puede eliminar la línea con el comando de import del archivo stdafx.h. En algunos casos, es necesario editar el archivo SimpleServer.tlh ajustando la ruta de la línea #include "SimpleServer.tli" casi al final del archivo. |
stdafx.h |
... #import "C:\\SimpleServer\\Release\\SimpleServer.dll" |
Step B |
From Solution Explorer add the SimpleServer.tlh and SimpleServer.tli files using the context menu. Desde el Explorador de Soluciones agregue los archivos SimpleServer.tlh y SimpleServer.tli usando el menú de contexto. |
MathClient.h |
#pragma once //______________________________________ MathClient.h #include "Resource.h" #include "simpleserver.tlh" #include "simpleserver.tli" class MathClient: public Win::Dialog { public: MathClient() { ::CoInitialize(NULL); } ~MathClient() { ::CoUninitialize(); } ... }; |
MathClient.cpp |
... void MathClient::Window_Open(Win::Event& e) { SimpleServerLib::IMathFuncPtr MathFunc; HRESULT hr; wstring text; Com::Exception ex; double minimum = 0.0, maximum = 0.0, mean = 0.0, variance = 0.0; try { //______________________________________________ CreateInstance hr = MathFunc.CreateInstance(L"selo.Basica"); ex.ok(L"MathFunc.CreateInstance", hr); // MathFunc->Add(10.0); MathFunc->Add(8.0); MathFunc->Add(2.0); MathFunc->Add(5.0); // mean = MathFunc->GetMean(); variance = MathFunc->GetVariance(); minimum = MathFunc->GetMinimum(); maximum = MathFunc->GetMaximum(); Sys::Format(text, L"mean = %g\r\nvar = %g\r\nmin = %g\r\nmax = %g", mean, variance, minimum, maximum); this->MessageBox(text, L"MathClient", MB_OK); } catch(Com::Exception& excep) { excep.Display(hWnd, L"MathClient"); } catch(_com_error excep) { Com::Exception::Display(hWnd, excep, L"MathClient"); } } |
Problem 3 |
Create an html file called BasicaTest.htm. You can use Microsoft Visual Studio, Notepad or other program to create and edit the file. The web page will use the Simple Server library. Cree un archivo de html llamado BasicaTest.htm. Usted puede usar Microsoft Visual Studio, El block de notas u otro programa para crear y editar el archivo. La página web usará la librería Simple Server. |
BasicaTest.htm |
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Basica</title> <script type="text/javascript"> var mathFunc = new ActiveXObject("selo.Basica"); if (mathFunc == null) { alert("The ActiveXObject selo.Basica is null"); } function display() { //____________________________________________ Get the textboxes var tbxX = document.getElementById("tbxX"); var tbxMean = document.getElementById("tbxMean"); var tbxVariance = document.getElementById("tbxVariance"); var tbxMinimum = document.getElementById("tbxMinimum"); var tbxMaximum = document.getElementById("tbxMaximum"); if (tbxX == null) return; if (tbxMean == null) return; if (tbxVariance == null) return; if (tbxMinimum == null) return; if (tbxMaximum == null) return; //_________________________________________ Add the value var x = parseFloat(tbxX.value); mathFunc.Add(x); //_________________________________________ Retrieve the values var mean = mathFunc.Mean; var variance = mathFunc.Variance; var minimum = mathFunc.Minimum; var maximum = mathFunc.Maximum; //_________________________________________ Display tbxMean.value = mean.toString(); tbxVariance.value = variance.toString(); tbxMinimum.value = minimum.toString(); tbxMaximum.value = maximum.toString(); // tbxX.value = ""; } </script> </head> <body> <input type="text" id="tbxX" name="tbxX" /><input type="button" name="Add" value="Add" onclick="display()" /><br /> Mean = <input type="text" id="tbxMean" name="tbxMean" /><br /> Variance = <input type="text" id="tbxVariance" name="tbxVariance" /><br /> Minimum = <input type="text" id="tbxMinimum" name="tbxMinimum" /><br /> Maximum = <input type="text" id="tbxMaximum" name="tbxMaximum" /><br /> </body> </html> |